using System;
using System.Drawing;
using System.Drawing.Imaging;

using ColladaDotNet.OpenTKMapping;

using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

namespace ColladaDotNet.ContentPipeline
{
	public class Renderer: IDisposable
	{
		int width = 256;
		int height = 512;

		int FBOHandle;
		int ColorTexture;
		int DepthTexture;

		public Renderer(int width, int height)
		{
			this.width = width;
			this.height = height;
			CheckWindow();
		}

		public Bitmap GetBitmap()
		{
			if (FBOHandle == 0)
			{
				Bitmap bmp2 = new Bitmap(width,height);
				return bmp2;
			}
			//GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
			Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
			BitmapData data = bmp.LockBits(
					new Rectangle(0, 0, width, height),
					ImageLockMode.WriteOnly,
					System.Drawing.Imaging.PixelFormat.Format32bppArgb);
			GL.ReadPixels(0, 0, width, height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
			bmp.UnlockBits(data);
			bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
			return bmp;
		}

		public void Render(COLLADA c,double time)
		{
			InitOpenGL();

			using (var doc = new Document())
			{
				doc.Load(c);
				var scene = doc.VisualScene;
				if (scene != null)
					scene.Render((double)width / (double)height, time);
			}

		}


		private void InitOpenGL()
		{
			// Create Color Tex
			if (ColorTexture == 0)
			{
				GL.GenTextures(1, out ColorTexture);
				GL.BindTexture(TextureTarget.Texture2D, ColorTexture);
				GL.TexImage2D(
						TextureTarget.Texture2D,
						0,
						PixelInternalFormat.Rgba8,
						width,
						height,
						0,
						OpenTK.Graphics.OpenGL.PixelFormat.Rgba,
						PixelType.UnsignedByte,
						IntPtr.Zero);
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);
				// GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D );
			}

			// Create Depth Tex
			if (DepthTexture == 0)
			{
				GL.GenTextures(1, out DepthTexture);
				GL.BindTexture(TextureTarget.Texture2D, DepthTexture);
				GL.TexImage2D(
						TextureTarget.Texture2D,
						0,
						(PixelInternalFormat)All.DepthComponent32,
						width,
						height,
						0,
						OpenTK.Graphics.OpenGL.PixelFormat.DepthComponent,
						PixelType.UnsignedInt,
						IntPtr.Zero);
				// things go horribly wrong if DepthComponent's Bitcount does not match the main Framebuffer's Depth
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
				GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);
				// GL.Ext.GenerateMipmap( GenerateMipmapTarget.Texture2D );
			}

			if (FBOHandle == 0)
			{
				GL.Ext.GenFramebuffers(1, out FBOHandle);
				GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, FBOHandle);
				GL.Ext.FramebufferTexture2D(
						FramebufferTarget.FramebufferExt,
						FramebufferAttachment.ColorAttachment0Ext,
						TextureTarget.Texture2D,
						ColorTexture,
						0);
				GL.Ext.FramebufferTexture2D(
						FramebufferTarget.FramebufferExt,
						FramebufferAttachment.DepthAttachmentExt,
						TextureTarget.Texture2D,
						DepthTexture,
						0);
			}
			GL.Enable(EnableCap.CullFace);
			GL.Enable(EnableCap.DepthTest);

			GL.Viewport(0, 0, width, height);
			GL.ClearColor(0f, 0f, 0f, 0f);
			GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
		}

		private static void CheckWindow()
		{
			if (hidden == null)
				hidden = new GameWindow(10, 10, GraphicsMode.Default, "OpenTK | Hidden input window", GameWindowFlags.Default, DisplayDevice.Default);
		}

		private static GameWindow hidden;

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		/// <filterpriority>2</filterpriority>
		public void Dispose()
		{
			if (FBOHandle != 0)
			{
				GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);
				GL.Ext.DeleteFramebuffers(1, new int []{FBOHandle});
				FBOHandle = 0;
			}
			if (ColorTexture != 0)
			{
				GL.DeleteTexture(ColorTexture);
				ColorTexture = 0;
			}
			if (DepthTexture != 0)
			{
				GL.DeleteTexture(DepthTexture);
				DepthTexture = 0;
			}
		}
	}
}